package com.hqyj.javaSpringBoot.modules.common.entiy;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;

import javax.persistence.*;
import java.io.Serializable;
import java.time.LocalDateTime;

/**
 *  @MappedSuperclass标识基类（父类），不能有 @Entity 和 @Table，子 类会自动映射父类属性；
 *
 *  序列化
 *  Serializable一个对象序列化的接口，一个类只有实现了Serializable接口，它的对象才能被序列化。
 *
 *  什么是序列化
 *     序列化是将对象状态转换为可保持或传输的格式的过程。
 *     与序列化相对的是反序列化，它将流转换为对象。这两个过程结合起来，可以轻松地存储和传输数据。
 */
@MappedSuperclass
public class AbstractEntity implements Serializable {

    /**
     * @Id 标注用于声明一个实体类的属性映射为数据库的主键列。
     *
     * @GeneratedValue 用于标注主键的生成策略，通过strategy 属性指定。
     * 默认情况下，JPA 自动选择一个最适合底层数据库的主键生成策略：SqlServer对应identity，MySQL 对应 auto increment。
     * IDENTITY：采用数据库ID自增长的方式来自增主键字段，Oracle 不支持这种方式；
     * AUTO： JPA自动选择合适的策略，是默认选项；
     * SEQUENCE：通过序列产生主键，通过@SequenceGenerator 注解指定序列名，MySql不支持这种方式
     * TABLE：通过表产生主键，框架借由表模拟序列产生主键，使用该策略可以使应用更易于数据库移植。
     * 注释可以写在属性之上，或者getter方法之上
     *
     * @Column:标识实体类中属性与数据表中字段的对应关系，可以标注在属性或getter方法前面
     * nullable() default true;//该字段是否可以为null值，默认为true
     * updatable() default true;//在使用“UPDATE”脚本插入数据时，是否需要更新该字段的值
     *       //insertable和updatable属性一般多用于只读的属性，例如主键和外键等。这些字段的值通常是自动生成的
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(nullable = false,updatable = false)
    private int id;

    /**
     * LocalDateTime.parse()对日期进行解析，而DateTimeFormatter内置没有yyyy-MM-dd HH:mm:ss此日期格式，
     * 因此出现以上异常，解决办法需要重写LocalDateTimeDeserializer类，指定我们需要的日期格式对其进行解析。
     * @JsonSerialize(using = CustomLocalDateTimeSerializer.class)
     * @JsonDeserialize(using = CustomLocalDateTimeDeserializer.class)
     */
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    @Column(updatable = false)
    private LocalDateTime createDate;

    /**
     * @PrePersist可帮助我们在持久化之前自动填充实体属性。
     * @PreUpdate用于为相应的生命周期事件指定回调方法。
     *      如果要每次更新实体时更新实体的属性，可以使用@PreUpdate注释。
     *      使用该注释，您不必在每次更新用户实体时显式更新相应的属性。
     */
    @PrePersist
    public void preInsert(){
        //给创建时间赋予当前系统时间
        setCreateDate(LocalDateTime.now());
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public LocalDateTime getCreateDate() {
        return createDate;
    }

    public void setCreateDate(LocalDateTime createDate) {
        this.createDate = createDate;
    }
}
